home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d20
/
bsrc_250.arc
/
ASYNC.C
next >
Wrap
C/C++ Source or Header
|
1991-09-16
|
21KB
|
714 lines
/*--------------------------------------------------------------------------*/
/* */
/* */
/* ------------ Bit-Bucket Software, Co. */
/* \ 10001101 / Writers and Distributors of */
/* \ 011110 / Freely Available<tm> Software. */
/* \ 1011 / */
/* ------ */
/* */
/* (C) Copyright 1987-91, Bit Bucket Software Co., a Delaware Corporation. */
/* */
/* */
/* This module was written by Peter Fitzsimmons */
/* */
/* */
/* BinkleyTerm OS/2 Async Comm I/O Routines */
/* */
/* */
/* For complete details of the licensing restrictions, please refer */
/* to the License agreement, which is published in its entirety in */
/* the MAKEFILE and BT.C, and also contained in the file LICENSE.250. */
/* */
/* USE OF THIS FILE IS SUBJECT TO THE RESTRICTIONS CONTAINED IN THE */
/* BINKLEYTERM LICENSING AGREEMENT. IF YOU DO NOT FIND THE TEXT OF */
/* THIS AGREEMENT IN ANY OF THE AFOREMENTIONED FILES, OR IF YOU DO */
/* NOT HAVE THESE FILES, YOU SHOULD IMMEDIATELY CONTACT BIT BUCKET */
/* SOFTWARE CO. AT ONE OF THE ADDRESSES LISTED BELOW. IN NO EVENT */
/* SHOULD YOU PROCEED TO USE THIS FILE WITHOUT HAVING ACCEPTED THE */
/* TERMS OF THE BINKLEYTERM LICENSING AGREEMENT, OR SUCH OTHER */
/* AGREEMENT AS YOU ARE ABLE TO REACH WITH BIT BUCKET SOFTWARE, CO. */
/* */
/* */
/* You can contact Bit Bucket Software Co. at any one of the following */
/* addresses: */
/* */
/* Bit Bucket Software Co. FidoNet 1:104/501, 1:343/491 */
/* P.O. Box 460398 AlterNet 7:491/0 */
/* Aurora, CO 80046 BBS-Net 86:2030/1 */
gg/* Internet f491.n343.z1.fidonet.org */
/* */
/* Please feel free to contact us at any time to share your comments about */
/* our software and/or licensing policies. */
/* */
/*--------------------------------------------------------------------------*/
#ifndef OS_2
#pragma message("This Module For OS/2")
#else
#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
#define INCL_DOS
#define INCL_DOSDEVICES
#define INCL_DOSDEVIOCTL
#define INCL_DOSSEMAPHORES
#define INCL_NOPM
#include <os2.h>
#include "bink.h"
#include "com.h"
#include "async.h"
/*--------------------------------------------------------*
* This file contains the operating system specific *
* serial communications routines for OS/2. *
* *
* (C) Copyright Peter Fitzsimmons Sun 04-16-1989 *
* *
* Add-ins for BinkleyTerm on Sat 05-06-1989 *
* *
* Worked over once again on 06/06-91, trying to get the *
* same effect as the Rev 6 FOSSIL in it *
*--------------------------------------------------------*/
/* This one has excellent send or receive, even with 8088 */
/* but the xmit rate is a bit low in Janus w/o SetPrty. */
/* #define DEBUG */ /* Exposes a bit more about ASYNC comm */
/* #define MultiWrt */ /* Not always reliable */
extern void status_line (char *,...);
extern void com_kick (void);
/* Private data */
/* static HFILE hfComHandle = -1; */ /* handle from DosOpen() */
HFILE hfComHandle = -1; /* handle from DosOpen() */
/* transmitter stuff */
#define TSIZE 8192
static unsigned char tBuf[TSIZE];
static unsigned char zTxBuf[TSIZE];
static int zpos = 0;
static int tBufsize = 0;
static unsigned int TQSize = 0;
/* static HSEM WriteSem = 0; */
ULONG WriteSem = 0;
/* receiver stuff */
#define RSIZE 8192
static unsigned char rbuf[RSIZE];
static USHORT rpos = 0;
static int rbufsize = 0;
static USHORT Rbytes = 0;
static word RQBbytes = 0;
static word RQBbyte2 = 0;
#ifdef DEBUG
#define debug_msg(m,c) status_line("!" m, c)
#define IOCtl(func, data, parm) _ioctl(#func, func, (void far *) data, (void far *) parm)
static int _ioctl(char *funcname, int func, void far * data, void far * parm)
{
int i;
if (i = DosDevIOCtl((PVOID) data, (PVOID) parm, func, IOCTL_ASYNC, (HFILE) hfComHandle)) {
printf("ioctl(%s) err(0x%04x)\n", funcname, i);
status_line("!ioctl(%s) err(0x%04x)", funcname, i);
}
return (i);
}
#else
#define debug_msg(m,c)
#define IOCtl(func, data, parm) DosDevIOCtl((PVOID) data, (PVOID) parm, func, IOCTL_ASYNC, (HFILE) hfComHandle)
#endif
static int com_getDCB(struct _DCBINFO far * dcb);
static int com_setDCB(struct _DCBINFO far * dcb);
/* com_init() : Intialize communications port. Baud rate is preserved.
* int port : Hardware port (0 based) to init
* -OR- char *unc : Full UNC \\networkId\modemId to init.
*
* if unc==NULL, port is used. if unc != NULL, unc is used
*/
int com_init(int port, char far *unc)
{
char str[30];
char *s;
USHORT ActionTaken; /* action: returned by OS/2 */
USHORT stat;
DCBINFO sDCB;
RXQUEUE q;
cputs("\033[1;33mOS/2 FOSSIL emulator for BinkleyTerm, Peter Fitzsimmons (1:250/628)\033[0m\r\n");
sprintf(str, "COM%d", port + 1);
if (!unc)
unc = str;
#ifdef DEBUG
stat = DosOpen((PSZ) unc,(PHFILE) &hfComHandle,(PUSHORT) &ActionTaken, 0L, 0, 0x0001, 0x4012, 0L);
#else
stat = DosOpen((PSZ) unc,(PHFILE) &hfComHandle,(PUSHORT) &ActionTaken, 0L, 0, 0x0001, 0x6012, 0L);
#endif
if (stat) {
hfComHandle = -1;
printf("com_init() : DosOpen() error 0x%04x on '%s'\n", stat, unc);
return (FALSE);
}
(void) DosSemClear((HSEM) &WriteSem);
if (!IOCtl(ASYNC_GETINQUECOUNT, (PVOID) &q, (PVOID) 0L)) {
s = getenv("RBUF");
if (s)
rbufsize = min( RSIZE, atoi(s));
else
rbufsize = RSIZE;
RQBbytes = min( RSIZE, rbufsize);
RQBbyte2 = RQBbytes/2;
#ifdef DEBUG
printf("com_init() : ASYNC Input Buffer size is %d'\n", q.cb);
#endif
}
if (!IOCtl(ASYNC_GETOUTQUECOUNT, (PVOID) &q, (PVOID) 0L)) {
s = getenv("TBUF");
if (s)
tBufsize = min( TSIZE, atoi(s));
else
tBufsize = TSIZE;
/* TQSize = min(TSIZE, q.cb/2); */ /* WRA */
TQSize = min(TSIZE, q.cb-16);
#ifdef DEBUG
printf("com_init() : ASYNC Output Buffer size is %d'\n", q.cb);
#endif
}
com_XON_disable();
com_getDCB((struct _DCBINFO far *) &sDCB);
/* turn off IDSR, ODSR */
/* sDCB.fbCtlHndShake &= ~(MODE_DSR_HANDSHAKE | MODE_DSR_SENSITIVITY); */
/* raise DTR, CTS output flow control */
/* sDCB.fbCtlHndShake |= (MODE_DTR_CONTROL | MODE_CTS_HANDSHAKE); */
/* turn off XON/XOFF flow control, error replacement off, null
* stripping off, break replacement off */
sDCB.fbFlowReplace &= ~(MODE_AUTO_TRANSMIT | MODE_AUTO_RECEIVE |
MODE_ERROR_CHAR | MODE_NULL_STRIPPING |
MODE_BREAK_CHAR);
/* RTS enable */
/* sDCB.fbFlowReplace |= MODE_RTS_CONTROL; */
/* sDCB.fbTimeout |= (MODE_NO_WRITE_TIMEOUT | MODE_NOWAIT_READ_TIMEOUT); */
sDCB.fbTimeout |= (MODE_NOWAIT_READ_TIMEOUT);
sDCB.fbTimeout &= ~(MODE_NO_WRITE_TIMEOUT);
sDCB.usReadTimeout = 1000;
sDCB.usWriteTimeout = 1000;
com_setDCB((struct _DCBINFO far *) &sDCB);
return (!stat);
}
void com_DTR_on(void)
{
DCBINFO sDCB;
com_getDCB((struct _DCBINFO far *) &sDCB);
sDCB.fbCtlHndShake |= MODE_DTR_CONTROL; /* raise DTR */
com_setDCB((struct _DCBINFO far *) &sDCB);
}
void com_DTR_off(void)
{
DCBINFO sDCB;
com_getDCB((struct _DCBINFO far *) &sDCB);
sDCB.fbCtlHndShake &= ~MODE_DTR_CONTROL; /* lower DTR */
com_setDCB((struct _DCBINFO far *) &sDCB);
}
/* close communications channel. Baud rate is preserved. */
int com_fini(void)
{
int stat;
if (!(hfComHandle == -1)) {
/* com_wait(); : */
while ((!com_out_empty()) && com_online())
DosSleep (1L);
while ((DosSemWait((HSEM) &WriteSem, 0L)) && (com_online()))
DosSleep (1L);
com_clear_in();
com_clear_out();
stat = DosClose(hfComHandle);
if (stat) {
hfComHandle = -1;
debug_msg("DosClose() error 0x%04x", stat);
return (FALSE);
}
hfComHandle = -1;
}
return(TRUE);
}
long com_cur_baud(void)
{
USHORT rate = 0;
IOCtl(ASYNC_GETBAUDRATE, (PVOID) &rate, (PVOID) 0L);
return ((long) rate);
}
/* com_set_baud() :
*
* rate = 110..19200
* parity = N, E, O, M, S (none,even, odd, mark, space)
* databits = 5..8
* stopbits = 1..2
*
*/
int com_set_baud(unsigned rate, char parity, int databits, int stopbits)
{
int stat;
struct _LINECONTROL {
BYTE bDataBits;
BYTE bParity;
BYTE bStopBits;
BYTE fbTransBreak;
} lc;
stat = IOCtl(ASYNC_SETBAUDRATE, (PVOID) 0L, (PVOID) &rate);
if (stat) {
return (FALSE);
}
lc.bDataBits = (BYTE) databits;
switch (stopbits) {
case 1:
lc.bStopBits = 0;
break;
case 2:
lc.bStopBits = 2;
break;
default:
if (databits == 5)
lc.bStopBits = 1;
}
lc.fbTransBreak = 0;
switch (toupper(parity)) {
case 'N':
lc.bParity = 0;
break;
case 'O':
lc.bParity = 1;
break;
case 'E':
lc.bParity = 2;
break;
case 'M':
lc.bParity = 3;
break;
case 'S':
lc.bParity = 4;
break;
default:
debug_msg("Bad parity '%c'", parity);
return (FALSE);
}
stat = IOCtl(ASYNC_SETLINECTRL, (PVOID) 0L, (PVOID) &lc);
if (stat) {
return (FALSE);
}
return (TRUE);
}
static int com_getDCB(struct _DCBINFO far * dcb)
{
int stat;
stat = IOCtl(ASYNC_GETDCBINFO, (PVOID) dcb, (PVOID) 0L);
return (!stat);
}
static int com_setDCB(struct _DCBINFO far * dcb)
{
int stat;
stat = IOCtl(ASYNC_SETDCBINFO, (PVOID) 0L, (PVOID) dcb);
return (!stat);
}
void com_XON_disable(void)
{
DCBINFO sDCB;
if (com_getDCB((struct _DCBINFO far *) &sDCB)) {
/* disable auto Xmit and recv flow control */
sDCB.fbFlowReplace &= ~(MODE_AUTO_TRANSMIT | MODE_AUTO_RECEIVE);
com_setDCB((struct _DCBINFO far *) &sDCB);
}
com_kick();
}
void com_XON_enable(void)
{
DCBINFO sDCB;
if (com_getDCB((struct _DCBINFO far *) &sDCB)) {
/* enable auto Xmit and recv flow control */
sDCB.fbFlowReplace |= (MODE_AUTO_TRANSMIT | MODE_AUTO_RECEIVE);
com_setDCB((struct _DCBINFO far *) &sDCB);
}
}
/* nuke receive buffer */
void com_clear_in(void)
{
int stat;
char FlushParm = 0; /* param to flush IOCTL function */
Rbytes = rpos = 0;
if (hfComHandle == -1)
return;
stat = DosDevIOCtl((PVOID) 0L, (PVOID) &FlushParm, DEV_FLUSHINPUT, IOCTL_GENERAL, hfComHandle);
if (stat) {
debug_msg("DEV_FLUSHINPUT err 0x%04x", stat);
}
}
/* com_getbuf() : return negative value if error */
int com_getbuf(void)
{
int stat = 0;
RXQUEUE q;
USHORT Rbytet;
if (rpos == Rbytes) /* If buffer empty, */
rpos = Rbytes = 0; /* reset pointers */
Rbytet = Rbytes; /* Save old count */
Rbytes = 0; /* Clear new count */
if (!(IOCtl(ASYNC_GETINQUECOUNT, (PVOID) &q, (PVOID) 0L))) {
if (q.cch > 0)
stat = DosRead(hfComHandle, rbuf+Rbytet, (USHORT) min(RQBbytes-Rbytet,q.cch), &Rbytes);
else
return (-1);
} else
return (-1);
if (stat && !Rbytes && (!(stat==ERROR_MORE_DATA))) {
debug_msg("DosRead() error 0x%04x", stat);
return (-1);
}
Rbytes += Rbytet;
return (TRUE);
}
/* com_getchar() : return negative value if error */
int com_getchar(void)
{
if (rpos != Rbytes)
return ((int) rbuf[rpos++]);
if (com_getbuf() == TRUE)
return ((int) rbuf[rpos++]);
return (-1);
}
/*non destructive read ahead; no wait */
int com_peek(void)
{
int c;
if (!com_char_avail())
c = -1;
else {
c = com_getchar();
if (c != -1)
rpos--;
}
return (c);
}
/* if RXQueue over half full, return TRUE */
bool com_in_check(void)
{
RXQUEUE q;
if (IOCtl(ASYNC_GETINQUECOUNT, (PVOID) &q, (PVOID) 0L))
return (FALSE);
return ((bool)((q.cch > RQBbyte2) ? TRUE : FALSE));
}
/* return number of chars in input buffer */
int com_char_avail(void)
{
RXQUEUE q;
if (rpos < Rbytes)
return (Rbytes-rpos);
return ((!(IOCtl(ASYNC_GETINQUECOUNT, (PVOID) &q, (PVOID) 0L))) ? q.cch : 0 );
}
/* return non 0 value if carrier detected */
bool com_online(void)
{
BYTE msr;
if (hfComHandle == -1)
return(FALSE);
if (IOCtl(ASYNC_GETMODEMINPUT, (PVOID) &msr, (PVOID) 0L))
return(FALSE);
return((bool) (msr & DCD_ON));
}
/* com_break() : start break if on==TRUE, stop break if on==FALSE */
void com_break(int on)
{
int cmd;
USHORT comerr;
cmd = (on) ? ASYNC_SETBREAKON : ASYNC_SETBREAKOFF;
IOCtl(cmd, (PVOID) &comerr, (PVOID) 0L);
}
/* com_out_empty() : return TRUE if output buffer is empty */
bool com_out_empty(void)
{
RXQUEUE q;
/* Service Inbound side if necessary */
if (com_in_check())
(void) com_getbuf();
if (DosSemWait((HSEM) &WriteSem, 1L) && !com_online ()) /* WRA 6/14/91 */
return (TRUE);
if (IOCtl(ASYNC_GETOUTQUECOUNT, (PVOID) &q, (PVOID) 0L))
return (TRUE);
return ((bool) (q.cch == 0));
}
/* com_out_full() : return TRUE if output buffer is full */
bool com_out_full(void)
{
RXQUEUE q;
if (com_in_check())
(void) com_getbuf();
if (IOCtl(ASYNC_GETOUTQUECOUNT, (PVOID) &q, (PVOID) 0L))
return (FALSE);
return ((bool) (q.cch == q.cb));
}
/* nuke transmit buffer */
void com_clear_out(void)
{
char FlushParm = 0; /* param to flush IOCTL function */
int stat;
zpos = 0;
DosSemClear((HSEM) &WriteSem);
if (hfComHandle == -1)
return;
stat = DosDevIOCtl((PVOID) 0L, (PVOID) &FlushParm, DEV_FLUSHOUTPUT, IOCTL_GENERAL, hfComHandle);
if (stat) {
debug_msg("DEV_FLUSHOUTPUT err 0x%04x", stat);
}
com_kick ();
}
/* com_putc_now() : disregard any buffering and send a byte now damnit! */
/* this function should be called only during emergencies...like when
* trying to cancel a file transfer
*/
/* Since the equivalent is a Com_ call, which in DOS is unsigned... */
unsigned com_putc_now(byte c)
{
return (!IOCtl(ASYNC_TRANSMITIMM, (PVOID) 0L, (PVOID) &c));
}
/* com_putc() : output to com port */
/* This function is very slow..where possile, write to com port in blocks
* using com_write() instead...especially above 2400 bps
*/
void com_putc(byte c)
{
static USHORT bytes;
int stat;
RXQUEUE q;
do {
if (com_in_check())
(void) com_getbuf();
} while(com_online () && DosSemWait((HSEM) &WriteSem, 0L));
do {
if (com_in_check())
(void) com_getbuf();
if (IOCtl(ASYNC_GETOUTQUECOUNT, (PVOID) &q, (PVOID) 0L))
return;
if (q.cch >= q.cb)
{
com_kick ();
DosSleep (1L);
}
} while ((q.cch >= q.cb) && com_online ());
/*
* DosWriteAsync() didn't work here.
*/
stat = DosWrite(hfComHandle, &c, 1, &bytes);
if (stat)
debug_msg("DosWrite() err 0x%04x", stat);
}
/* com_write() : buffered block write */
void com_write(char *buf, unsigned int num, int carcheck)
{
static USHORT err, bytes;
#ifdef MultiWrt
unsigned int tnum = 0;
#endif
do {
if ((carcheck) && !com_online())
return;
if (com_in_check())
(void) com_getbuf();
} while(DosSemWait((HSEM) &WriteSem, 1L));
(void) DosSemRequest((HSEM) &WriteSem, 0L);
#ifdef MultiWrt
while (tnum+TQSize > num+TQSize) {
memcpy (tBuf, &buf[tnum], TQSize);
DosWriteAsync(hfComHandle, (PULONG) &WriteSem, &err, tBuf, TQSize, &bytes);
tnum += TQSize;
do {
if ((carcheck) && !com_online())
return;
if (com_in_check())
(void) com_getbuf();
} while(DosSemWait((HSEM) &WriteSem, 1L));
(void) DosSemRequest((HSEM) &WriteSem, 0L);
}
memcpy (tBuf, &buf[tnum], num-tnum);
DosWriteAsync(hfComHandle, (PULONG) &WriteSem, &err, tBuf, num-tnum, &bytes);
#else
memcpy (tBuf, buf, num);
DosWriteAsync(hfComHandle, (PULONG) &WriteSem, &err, tBuf, num, &bytes);
#endif
}
/* wait for output buffer to empty */
void com_wait(void)
{
while ((!com_out_empty()) && com_online())
DosSleep (1L);
}
/* force transmitter to go */
void com_kick(void)
{
int stat;
if (hfComHandle == -1)
return;
stat = IOCtl(ASYNC_STARTTRANSMIT, (PVOID) 0L, (PVOID) 0L);
if (stat) {
debug_msg("ASYNC_STARTTRANSMIT err 0x%04x", stat);
}
}
extern unsigned int baud;
extern unsigned int comm_bits;
extern unsigned int parity;
extern unsigned int stop_bits;
extern struct baud_str btypes[];
void MDM_ENABLE(unsigned rate)
{
char _parity;
int databits;
int stopbits;
if (hfComHandle == -1)
return;
com_clear_out();
com_clear_in();
databits = 7 + (comm_bits == BITS_8);
stopbits = 1 + (stop_bits == STOP_2);
switch (parity) {
case NO_PARITY:
_parity = 'N';
break;
case ODD_PARITY:
_parity = 'O';
break;
case EVEN_PARITY:
_parity = 'E';
break;
default:
_parity = 'N';
}
com_set_baud(rate, _parity, databits, stopbits);
}
void MDM_DISABLE(void)
{
if (hfComHandle == -1)
return;
com_clear_out();
com_clear_in();
com_fini();
}
/* zsend.c uses BUFFER_BYTE and UNBUFFER_BYTES...good idea. */
void BUFFER_BYTE(unsigned char ch)
{
if (zpos == tBufsize)
UNBUFFER_BYTES();
zTxBuf[zpos++] = ch;
}
void UNBUFFER_BYTES(void)
{
if (com_online() && zpos)
(zpos == 1) ? (com_putc(zTxBuf[0])) : (com_write(zTxBuf,zpos,1)) ;
zpos = 0;
}
unsigned Cominit(int port, int failsafe)
{
failsafe = failsafe;
if (hfComHandle != -1)
com_fini();
if (port == 0xff || com_init(port, NULL))
return (0x1954);
else
return (0);
}
#endif /* OS_2 */